#ifndef _AE_SERIALS_H_
#define _AE_SERIALS_H_
#include <memory>
#include <string.h>
#include "AeProtols.h"


/**
* @brief:
* Packer and unpacker for protocols.
*
* PC   Pack                  Robot
*      ------------------->
*      <------------------
*      Unpack
*
* [DATAGRAM]
* 0xFB 0xBF len(1B) cmd(1B) params(N*B) checksum(1B) 0xED
* Checksum = LOW_B(len+cmd+params)
*/
class CProtoSerial
{
public:
	CProtoSerial();
	virtual ~CProtoSerial();

	static uint8_t Checksum(uint32_t size, const uint8_t *data);

	// Version
	static AeRet_t PackGetVersion(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackGetVersion(uint32_t size, const uint8_t *data, uint32_t &version);

	// Storage
	static AeRet_t PackGetStorage(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackGetStorage(uint32_t size, const uint8_t *data, uint32_t &total, uint32_t &used);

	// Action
	static AeRet_t PackGetActions(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackGetActions(uint32_t size, const uint8_t *data);
	static AeRet_t PackGetactSending(uint32_t &size, uint8_t *data, uint32_t actLen, const char *actStr, const AeActHeader_t &header);
	static AeRet_t UnpackGetactSending(uint32_t size, const uint8_t *data, char *actStr, AeActHeader_t &header);
	static AeRet_t PackGetactFinished(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackGetactFinished(uint32_t size, const uint8_t *data);

	static AeRet_t PackPlayAction(uint32_t &size, uint8_t *data, uint32_t actLen, const char *actStr);
	static AeRet_t UnpackPlayAction(uint32_t size, const uint8_t *data);
	static AeRet_t PackPlayactSending(uint32_t &size, uint8_t *data, uint32_t total, uint32_t played);
	static AeRet_t UnpackPlayactSending(uint32_t size, const uint8_t *data, uint32_t &total, uint32_t &played);
	static AeRet_t PackPlayactFinished(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackPlayactFinished(uint32_t size, const uint8_t *data);

	static AeRet_t PackStopAction(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackStopAction(uint32_t size, const uint8_t *data);
	static AeRet_t PackCtrlAction(uint32_t &size, uint8_t *data, bool pause);
	static AeRet_t UnpackCtrlAction(uint32_t size, const uint8_t *data);
	static AeRet_t PackDeleteAction(uint32_t &size, uint8_t *data, uint32_t actLen, const char *actStr);
	static AeRet_t UnpackDeleteAction(uint32_t size, const uint8_t *data, char *actStr);

	static AeRet_t PackUploadAction(uint32_t &size, uint8_t *data, uint32_t actLen, const char *actStr, const AeActHeader_t &header);
	static AeRet_t UnpackUploadAction(uint32_t size, const uint8_t *data);
	static AeRet_t PackUploadactSending(uint32_t &size, uint8_t *data, uint32_t actLen, const char *actStr, const AeActPose_t &pose);
	static AeRet_t UnpackUploadactSending(uint32_t size, const uint8_t *data, uint32_t &seq);
	static AeRet_t PackUploadactFinished(uint32_t &size, uint8_t *data, uint32_t actLen, const char *actStr);
	static AeRet_t UnpackUploadactFinished(uint32_t size, const uint8_t *data);

	// Voice
	static AeRet_t PackOffOnVoice(uint32_t &size, uint8_t *data, bool on);
	static AeRet_t UnpackOffOnVoice(uint32_t size, const uint8_t *data);
	static AeRet_t PackSetVolume(uint32_t &size, uint8_t *data, uint8_t volume);
	static AeRet_t UnpackSetVolume(uint32_t size, const uint8_t *data);
	static AeRet_t PackPlayMusic(uint32_t &size, uint8_t *data, uint8_t dir, uint8_t idx);
	static AeRet_t UnpackPlayMusic(uint32_t size, const uint8_t *data);
	static AeRet_t PackStopMusic(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackStopMusic(uint32_t size, const uint8_t *data);
	static AeRet_t PackCtrlMusic(uint32_t &size, uint8_t *data, bool pause);
	static AeRet_t UnpackCtrlMusic(uint32_t size, const uint8_t *data);

	// Servo
	static AeRet_t PackSetServoLed(uint32_t &size, uint8_t *data, uint8_t idx, bool on);
	static AeRet_t UnpackSetServoLed(uint32_t size, const uint8_t *data, uint8_t &idx);
	static AeRet_t PackSetServosLed(uint32_t &size, uint8_t *data, bool on);
	static AeRet_t UnpackSetServosLed(uint32_t size, const uint8_t *data);

	static AeRet_t PackSetServoAngle(uint32_t &size, uint8_t *data, uint8_t idx, uint16_t angle,
		uint32_t msec, uint32_t lckmsec);
	static AeRet_t UnpackSetServoAngle(uint32_t size, const uint8_t *data, uint8_t &idx);
	static AeRet_t PackSetServosAngle(uint32_t &size, uint8_t *data, uint16_t *angles, uint32_t msec, uint32_t lckmsec);
	static AeRet_t UnpackSetServosAngle(uint32_t size, const uint8_t *data, AeRet_t *rets);
	static AeRet_t PackGetServoAngle(uint32_t &size, uint8_t *data, uint8_t idx);
	static AeRet_t UnpackGetServoAngle(uint32_t size, const uint8_t *data, uint8_t &idx, uint16_t &angle);
	static AeRet_t PackGetServosAngle(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackGetServosAngle(uint32_t size, const uint8_t *data, uint16_t *angles);

	static AeRet_t PackSetServoOffset(uint32_t &size, uint8_t *data, uint8_t idx, int16_t offset);
	static AeRet_t UnpackSetServoOffset(uint32_t size, const uint8_t *data, uint8_t &idx);
	static AeRet_t PackSetServosOffset(uint32_t &size, uint8_t *data, int16_t *offsets);
	static AeRet_t UnpackSetServosOffset(uint32_t size, const uint8_t *data, AeRet_t *rets);
	static AeRet_t PackGetServoOffset(uint32_t &size, uint8_t *data, uint8_t idx);
	static AeRet_t UnpackGetServoOffset(uint32_t size, const uint8_t *data, uint8_t &idx, int16_t &offset);
	static AeRet_t PackGetServosOffset(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackGetServosOffset(uint32_t size, const uint8_t *data, int16_t *offsets);

	static AeRet_t PackLockServos(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackLockServos(uint32_t size, const uint8_t *data);
	static AeRet_t PackUnlockServos(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackUnlockServos(uint32_t size, const uint8_t *data);

	static AeRet_t PackGetServoFirmware(uint32_t &size, uint8_t *data, uint8_t idx);
	static AeRet_t UnpackGetServoFirmware(uint32_t size, const uint8_t *data, uint8_t &idx, uint32_t &firmware);
	static AeRet_t PackGetServosFirmware(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackGetServosFirmware(uint32_t size, const uint8_t *data, uint32_t *firmwares);
	
	// Teaching
	static AeRet_t PackStartTeach(uint32_t &size, uint8_t *data, uint32_t nameLen, const char *nameStr);
	static AeRet_t UnpackStartTeach(uint32_t size, const uint8_t *data, uint32_t &waitMs);
	static AeRet_t PackStopTeach(uint32_t &size, uint8_t *data);
	static AeRet_t UnpackStopTeach(uint32_t size, const uint8_t *data);
	static AeRet_t PackTeachSending(uint32_t &size, uint8_t *data, uint16_t *angles);
	static AeRet_t UnpackTeachSending(uint32_t size, const uint8_t *data, uint16_t *angles);

	// Moving
	static AeRet_t PackMoving(uint32_t &size, uint8_t *data, uint8_t move);
	static AeRet_t UnpackMoving(uint32_t size, const uint8_t *data, uint8_t &move);

protected:
	static void putU8(uint32_t &offset, uint8_t *data, uint8_t val);
	static void putU16(uint32_t &offset, uint8_t *data, uint16_t val);
	static void putU32(uint32_t &offset, uint8_t *data, uint32_t val);
	static void putString(uint32_t &offset, uint8_t *data, uint32_t len, const char *str);
	static void putHeader(uint32_t &offset, uint8_t *data, uint8_t len, uint8_t cmd);
	static void putTail(uint32_t &offset, uint8_t *data, uint8_t len);

	static bool check(uint32_t size, const uint8_t *data, uint32_t len);
	static void getU8(uint32_t &offset, const uint8_t *data, uint8_t &val);
	static void getU16(uint32_t &offset, const uint8_t *data, uint16_t &val);
	static void getU32(uint32_t &offset, const uint8_t *data, uint32_t &val);
	static void getString(uint32_t &offset, const uint8_t *data, char *str);
};

#endif

